package zhishuang.wang.sansi.tools.json.exception;

import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @Author Zhishuang.Wang
 * @Date 2023/7/5 11:19
 * @Email 1406110602@qq.com
 */

final class ParameterFormatter {
    static final String RECURSION_PREFIX = "[...";
    static final String RECURSION_SUFFIX = "...]";
    static final String ERROR_PREFIX = "[!!!";
    static final String ERROR_SEPARATOR = "=>";
    static final String ERROR_MSG_SEPARATOR = ":";
    static final String ERROR_SUFFIX = "!!!]";
    private static final char DELIM_START = '{';
    private static final char DELIM_STOP = '}';
    private static final char ESCAPE_CHAR = '\\';
    private static DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

    private ParameterFormatter() {
    }

    static int countArgumentPlaceholders(String messagePattern) {
        if (messagePattern == null) {
            return 0;
        } else {
            int length = messagePattern.length();
            int result = 0;
            boolean isEscaped = false;

            for(int i = 0; i < length - 1; ++i) {
                char curChar = messagePattern.charAt(i);
                if (curChar == '\\') {
                    isEscaped = !isEscaped;
                } else if (curChar == '{') {
                    if (!isEscaped && messagePattern.charAt(i + 1) == '}') {
                        ++result;
                        ++i;
                    }

                    isEscaped = false;
                } else {
                    isEscaped = false;
                }
            }

            return result;
        }
    }

    static int countArgumentPlaceholders2(String messagePattern, int[] indices) {
        if (messagePattern == null) {
            return 0;
        } else {
            int length = messagePattern.length();
            int result = 0;
            boolean isEscaped = false;

            for(int i = 0; i < length - 1; ++i) {
                char curChar = messagePattern.charAt(i);
                if (curChar == '\\') {
                    isEscaped = !isEscaped;
                    indices[0] = -1;
                    ++result;
                } else if (curChar == '{') {
                    if (!isEscaped && messagePattern.charAt(i + 1) == '}') {
                        indices[result] = i;
                        ++result;
                        ++i;
                    }

                    isEscaped = false;
                } else {
                    isEscaped = false;
                }
            }

            return result;
        }
    }

    static int countArgumentPlaceholders3(char[] messagePattern, int length, int[] indices) {
        int result = 0;
        boolean isEscaped = false;

        for(int i = 0; i < length - 1; ++i) {
            char curChar = messagePattern[i];
            if (curChar == '\\') {
                isEscaped = !isEscaped;
            } else if (curChar == '{') {
                if (!isEscaped && messagePattern[i + 1] == '}') {
                    indices[result] = i;
                    ++result;
                    ++i;
                }

                isEscaped = false;
            } else {
                isEscaped = false;
            }
        }

        return result;
    }

    static String format(String messagePattern, Object[] arguments) {
        StringBuilder result = new StringBuilder();
        int argCount = arguments == null ? 0 : arguments.length;
        formatMessage(result, messagePattern, arguments, argCount);
        return result.toString();
    }

    static void formatMessage2(StringBuilder buffer, String messagePattern, Object[] arguments, int argCount, int[] indices) {
        if (messagePattern != null && arguments != null && argCount != 0) {
            int previous = 0;

            for(int i = 0; i < argCount; ++i) {
                buffer.append(messagePattern, previous, indices[i]);
                previous = indices[i] + 2;
                recursiveDeepToString(arguments[i], buffer, (Set)null);
            }

            buffer.append(messagePattern, previous, messagePattern.length());
        } else {
            buffer.append(messagePattern);
        }
    }

    static void formatMessage3(StringBuilder buffer, char[] messagePattern, int patternLength, Object[] arguments, int argCount, int[] indices) {
        if (messagePattern != null) {
            if (arguments != null && argCount != 0) {
                int previous = 0;

                for(int i = 0; i < argCount; ++i) {
                    buffer.append(messagePattern, previous, indices[i]);
                    previous = indices[i] + 2;
                    recursiveDeepToString(arguments[i], buffer, (Set)null);
                }

                buffer.append(messagePattern, previous, patternLength);
            } else {
                buffer.append(messagePattern);
            }
        }
    }

    static void formatMessage(StringBuilder buffer, String messagePattern, Object[] arguments, int argCount) {
        if (messagePattern != null && arguments != null && argCount != 0) {
            int escapeCounter = 0;
            int currentArgument = 0;
            int i = 0;

            int len;
            for(len = messagePattern.length(); i < len - 1; ++i) {
                char curChar = messagePattern.charAt(i);
                if (curChar == '\\') {
                    ++escapeCounter;
                } else {
                    if (isDelimPair(curChar, messagePattern, i)) {
                        ++i;
                        writeEscapedEscapeChars(escapeCounter, buffer);
                        if (isOdd(escapeCounter)) {
                            writeDelimPair(buffer);
                        } else {
                            writeArgOrDelimPair(arguments, argCount, currentArgument, buffer);
                            ++currentArgument;
                        }
                    } else {
                        handleLiteralChar(buffer, escapeCounter, curChar);
                    }

                    escapeCounter = 0;
                }
            }

            handleRemainingCharIfAny(messagePattern, len, buffer, escapeCounter, i);
        } else {
            buffer.append(messagePattern);
        }
    }

    private static boolean isDelimPair(char curChar, String messagePattern, int curCharIndex) {
        return curChar == '{' && messagePattern.charAt(curCharIndex + 1) == '}';
    }

    private static void handleRemainingCharIfAny(String messagePattern, int len, StringBuilder buffer, int escapeCounter, int i) {
        if (i == len - 1) {
            char curChar = messagePattern.charAt(i);
            handleLastChar(buffer, escapeCounter, curChar);
        }

    }

    private static void handleLastChar(StringBuilder buffer, int escapeCounter, char curChar) {
        if (curChar == '\\') {
            writeUnescapedEscapeChars(escapeCounter + 1, buffer);
        } else {
            handleLiteralChar(buffer, escapeCounter, curChar);
        }

    }

    private static void handleLiteralChar(StringBuilder buffer, int escapeCounter, char curChar) {
        writeUnescapedEscapeChars(escapeCounter, buffer);
        buffer.append(curChar);
    }

    private static void writeDelimPair(StringBuilder buffer) {
        buffer.append('{');
        buffer.append('}');
    }

    private static boolean isOdd(int number) {
        return (number & 1) == 1;
    }

    private static void writeEscapedEscapeChars(int escapeCounter, StringBuilder buffer) {
        int escapedEscapes = escapeCounter >> 1;
        writeUnescapedEscapeChars(escapedEscapes, buffer);
    }

    private static void writeUnescapedEscapeChars(int escapeCounter, StringBuilder buffer) {
        while(escapeCounter > 0) {
            buffer.append('\\');
            --escapeCounter;
        }

    }

    private static void writeArgOrDelimPair(Object[] arguments, int argCount, int currentArgument, StringBuilder buffer) {
        if (currentArgument < argCount) {
            recursiveDeepToString(arguments[currentArgument], buffer, (Set)null);
        } else {
            writeDelimPair(buffer);
        }

    }

    static String deepToString(Object o) {
        if (o == null) {
            return null;
        } else if (o instanceof String) {
            return (String)o;
        } else {
            StringBuilder str = new StringBuilder();
            Set<String> dejaVu = new HashSet();
            recursiveDeepToString(o, str, dejaVu);
            return str.toString();
        }
    }

    private static void recursiveDeepToString(Object o, StringBuilder str, Set<String> dejaVu) {
        if (!appendSpecialTypes(o, str)) {
            if (isMaybeRecursive(o)) {
                appendPotentiallyRecursiveValue(o, str, dejaVu);
            } else {
                tryObjectToString(o, str);
            }

        }
    }

    private static boolean appendSpecialTypes(Object o, StringBuilder str) {
        if (o != null && !(o instanceof String)) {
            if (o instanceof CharSequence) {
                str.append((CharSequence)o);
                return true;
            } else if (o instanceof Integer) {
                str.append((Integer)o);
                return true;
            } else if (o instanceof Long) {
                str.append((Long)o);
                return true;
            } else if (o instanceof Double) {
                str.append((Double)o);
                return true;
            } else if (o instanceof Boolean) {
                str.append((Boolean)o);
                return true;
            } else if (o instanceof Character) {
                str.append((Character)o);
                return true;
            } else if (o instanceof Short) {
                str.append((Short)o);
                return true;
            } else if (o instanceof Float) {
                str.append((Float)o);
                return true;
            } else {
                return appendDate(o, str);
            }
        } else {
            str.append((String)o);
            return true;
        }
    }

    private static boolean appendDate(Object o, StringBuilder str) {
        if (!(o instanceof Date)) {
            return false;
        } else {
            Date date = (Date)o;
            str.append(dateTimeFormatter.format(date.toInstant().atZone(ZoneId.systemDefault())));
            return true;
        }
    }

    private static boolean isMaybeRecursive(Object o) {
        return o.getClass().isArray() || o instanceof Map || o instanceof Collection;
    }

    private static void appendPotentiallyRecursiveValue(Object o, StringBuilder str, Set<String> dejaVu) {
        Class<?> oClass = o.getClass();
        if (oClass.isArray()) {
            appendArray(o, str, dejaVu, oClass);
        } else if (o instanceof Map) {
            appendMap(o, str, dejaVu);
        } else if (o instanceof Collection) {
            appendCollection(o, str, dejaVu);
        }

    }

    private static void appendArray(Object o, StringBuilder str, Set<String> dejaVu, Class<?> oClass) {
        if (oClass == byte[].class) {
            str.append(Arrays.toString((byte[])((byte[])o)));
        } else if (oClass == short[].class) {
            str.append(Arrays.toString((short[])((short[])o)));
        } else if (oClass == int[].class) {
            str.append(Arrays.toString((int[])((int[])o)));
        } else if (oClass == long[].class) {
            str.append(Arrays.toString((long[])((long[])o)));
        } else if (oClass == float[].class) {
            str.append(Arrays.toString((float[])((float[])o)));
        } else if (oClass == double[].class) {
            str.append(Arrays.toString((double[])((double[])o)));
        } else if (oClass == boolean[].class) {
            str.append(Arrays.toString((boolean[])((boolean[])o)));
        } else if (oClass == char[].class) {
            str.append(Arrays.toString((char[])((char[])o)));
        } else {
            if (dejaVu == null) {
                dejaVu = new HashSet();
            }

            String id = identityToString(o);
            if (((Set)dejaVu).contains(id)) {
                str.append("[...").append(id).append("...]");
            } else {
                ((Set)dejaVu).add(id);
                Object[] oArray = (Object[])((Object[])o);
                str.append('[');
                boolean first = true;
                Object[] var7 = oArray;
                int var8 = oArray.length;

                for(int var9 = 0; var9 < var8; ++var9) {
                    Object current = var7[var9];
                    if (first) {
                        first = false;
                    } else {
                        str.append(", ");
                    }

                    recursiveDeepToString(current, str, new HashSet((Collection)dejaVu));
                }

                str.append(']');
            }
        }

    }

    private static void appendMap(Object o, StringBuilder str, Set<String> dejaVu) {
        if (dejaVu == null) {
            dejaVu = new HashSet();
        }

        String id = identityToString(o);
        if (((Set)dejaVu).contains(id)) {
            str.append("[...").append(id).append("...]");
        } else {
            ((Set)dejaVu).add(id);
            Map<?, ?> oMap = (Map)o;
            str.append('{');
            boolean isFirst = true;
            Iterator var6 = oMap.entrySet().iterator();

            while(var6.hasNext()) {
                Object o1 = var6.next();
                Map.Entry<?, ?> current = (Map.Entry)o1;
                if (isFirst) {
                    isFirst = false;
                } else {
                    str.append(", ");
                }

                Object key = current.getKey();
                Object value = current.getValue();
                recursiveDeepToString(key, str, new HashSet((Collection)dejaVu));
                str.append('=');
                recursiveDeepToString(value, str, new HashSet((Collection)dejaVu));
            }

            str.append('}');
        }

    }

    private static void appendCollection(Object o, StringBuilder str, Set<String> dejaVu) {
        if (dejaVu == null) {
            dejaVu = new HashSet();
        }

        String id = identityToString(o);
        if (((Set)dejaVu).contains(id)) {
            str.append("[...").append(id).append("...]");
        } else {
            ((Set)dejaVu).add(id);
            Collection<?> oCol = (Collection)o;
            str.append('[');
            boolean isFirst = true;

            Object anOCol;
            for(Iterator var6 = oCol.iterator(); var6.hasNext(); recursiveDeepToString(anOCol, str, new HashSet((Collection)dejaVu))) {
                anOCol = var6.next();
                if (isFirst) {
                    isFirst = false;
                } else {
                    str.append(", ");
                }
            }

            str.append(']');
        }

    }

    private static void tryObjectToString(Object o, StringBuilder str) {
        try {
            str.append(o.toString());
        } catch (Throwable var3) {
            handleErrorInObjectToString(o, str, var3);
        }

    }

    private static void handleErrorInObjectToString(Object o, StringBuilder str, Throwable t) {
        str.append("[!!!");
        str.append(identityToString(o));
        str.append("=>");
        String msg = t.getMessage();
        String className = t.getClass().getName();
        str.append(className);
        if (!className.equals(msg)) {
            str.append(":");
            str.append(msg);
        }

        str.append("!!!]");
    }

    static String identityToString(Object obj) {
        return obj == null ? null : obj.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(obj));
    }
}
